package com.panghl.service.impl;

import com.panghl.config.FileTypeUtil;
import com.panghl.config.MinioFileUtil;
import com.panghl.service.IMinioService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.time.LocalDate;
import java.util.Date;
import java.util.UUID;

@Slf4j
@Service
public class MinioServiceImpl implements IMinioService {

    private MinioFileUtil minioFileUtil;

    public MinioServiceImpl(MinioFileUtil minioFileUtil) {
        this.minioFileUtil = minioFileUtil;
    }

    /**
     * 文件上传
     *
     * @param file 文件对象
     */
    @Override
    public String upload(MultipartFile file) {
        try {
            //得到文件流
            InputStream is = file.getInputStream();
            //文件:201403/1910585304069fdj.png
            String fileName = file.getOriginalFilename();
            int lastIndexOf = fileName.lastIndexOf(".");
            //获取文件的后缀名 .jpg
            String suffix = fileName.substring(lastIndexOf);

            String uuid = UUID.randomUUID().toString().replace("-", "");
            int yyyy = LocalDate.now().getYear();
            int MM = LocalDate.now().getMonthValue();
            int dd = LocalDate.now().getDayOfMonth();

            String filePath = yyyy + "/" + MM + "/" + dd + "/" + uuid + suffix;

            //把文件放置Minio桶(文件夹)
            minioFileUtil.uploadFile(filePath, is);
            return filePath;
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage(), e);
            return "";
        }
    }

    /**
     * 文件下载
     *
     * @param filePath 文件路径
     * @param response 响应对象
     */
    @Override
    public Boolean download(String filePath, HttpServletResponse response) {
        try {
            response.setHeader("Content-Disposition", "attachment;filename=" + filePath);
            response.setContentType("application/force-download");
            response.setCharacterEncoding("UTF-8");
            minioFileUtil.write2OutputStream(filePath, response.getOutputStream());
            return Boolean.TRUE;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Boolean.FALSE;
        }
    }

    /**
     * 文件预览
     *
     * @param filePath 文件路径
     */
    @Override
    public Boolean preview(String filePath, String type, HttpServletResponse response) {
        try {
            // 无法交给浏览器直接预览的文件，直接转换为文件流下载
            if (!FileTypeUtil.SimpleFileTypeEnum.canDirectPreview(type)) {
                return download(filePath, response);
            }
            minioFileUtil.write2OutputStream(filePath, response.getOutputStream());

            return Boolean.TRUE;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Boolean.FALSE;
        }
    }

    /**
     * 预览
     * @param filePath
     * @param type
     * @param response
     * @param request
     */
    @Override
    public void preview2(String filePath, String type, HttpServletResponse response, HttpServletRequest request) {
        if (FileTypeUtil.FileTypeEnum.JPG.getFileType().equalsIgnoreCase(type)) {
            imgPreview(filePath, response, request);
        } else if (FileTypeUtil.FileTypeEnum.PDF.getFileType().equalsIgnoreCase(type)) {
            pdfPreview(filePath, response, request);
        } else if (FileTypeUtil.FileTypeEnum.MP4.getFileType().equalsIgnoreCase(type)) {
            mp4Preview(filePath, response, request);
        }
    }

    /**
     * 图片预览
     *
     * @param filePath
     * @param response
     * @param request
     */
    private void pdfPreview(String filePath, HttpServletResponse response, HttpServletRequest request) {
        response.reset();
        response.setContentType("application/pdf");
        imgPreview(filePath, response, request);
    }

    /**
     * 图片预览
     *
     * @param filePath
     * @param response
     * @param request
     */
    private void imgPreview(String filePath, HttpServletResponse response, HttpServletRequest request) {
        //获取文件信息
        File file = new File(filePath);
        if (file.exists()) {
            byte[] data = null;
            FileInputStream input = null;
            try {
                input = new FileInputStream(file);
                data = new byte[input.available()];
                input.read(data);
                response.getOutputStream().write(data);
                response.setHeader("content-disposition", "inline;filename=" + file.getName());
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            } finally {
                try {
                    if (input != null) {
                        input.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * mp4预览
     *
     * @param filePath
     * @param response
     * @param request
     */
    private void mp4Preview(String filePath, HttpServletResponse response, HttpServletRequest request) {
        ServletOutputStream out = null;
        RandomAccessFile randomFile = null;
        try {
            File file = new File(filePath);
            randomFile = new RandomAccessFile(file, "r");//只读模式
            long contentLength = randomFile.length();
            String range = request.getHeader("Range");
            int start = 0, end = 0;
            if (range != null && range.startsWith("bytes=")) {
                String[] values = range.split("=")[1].split("-");
                start = Integer.parseInt(values[0]);
                if (values.length > 1) {
                    end = Integer.parseInt(values[1]);
                }
            }
            int requestSize = 0;
            if (end != 0 && end > start) {
                requestSize = end - start + 1;
            } else {
                requestSize = Integer.MAX_VALUE;
            }

            response.setContentType("video/mp4");
            response.setHeader("Accept-Ranges", "bytes");
            response.setHeader("ETag", file.getName());
            response.setHeader("Last-Modified", new Date().toString());
            //第一次请求只返回content length来让客户端请求多次实际数据
            if (range == null) {
                response.setHeader("Content-length", contentLength + "");
            } else {
                //以后的多次以断点续传的方式来返回视频数据
                response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);//206
                long requestStart = 0, requestEnd = 0;
                String[] ranges = range.split("=");
                if (ranges.length > 1) {
                    String[] rangeDatas = ranges[1].split("-");
                    requestStart = Integer.parseInt(rangeDatas[0]);
                    if (rangeDatas.length > 1) {
                        requestEnd = Integer.parseInt(rangeDatas[1]);
                    }
                }
                long length = 0;
                if (requestEnd > 0) {
                    length = requestEnd - requestStart + 1;
                    response.setHeader("Content-length", "" + length);
                    response.setHeader("Content-Range",
                            "bytes " + requestStart + "-" + requestEnd + "/" + contentLength);
                } else {
                    length = contentLength - requestStart;
                    response.setHeader("Content-length", "" + length);
                    response.setHeader("Content-Range",
                            "bytes " + requestStart + "-" + (contentLength - 1) + "/" + contentLength);
                }
            }
            out = response.getOutputStream();
            int needSize = requestSize;
            randomFile.seek(start);
            while (needSize > 0) {
                byte[] buffer = new byte[4096];
                int len = randomFile.read(buffer);
                if (needSize < buffer.length) {
                    out.write(buffer, 0, needSize);
                } else {
                    out.write(buffer, 0, len);
                    if (len < buffer.length) {
                        break;
                    }
                }
                needSize -= buffer.length;
            }
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                }
            }
            if (randomFile != null) {
                try {
                    randomFile.close();
                } catch (IOException e) {
                }
            }
        }
        return;
    }

    /**
     * 文件删除
     *
     * @param filePath 文件路径
     */
    @Override
    public Boolean deleteFile(String filePath) {
        try {
            minioFileUtil.deleteFile(filePath);
            return Boolean.TRUE;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Boolean.FALSE;
        }
    }


}
